using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;

namespace Efficiency.Controls
{
	public class PercentHeightStackPanel: StackPanel
	{
		#region Attached Properties

		public static readonly DependencyProperty PercentHeightProperty = DependencyProperty.RegisterAttached(
			"PercentHeight",
			typeof(Double),
			typeof(PercentHeightStackPanel),
			new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));

		public static void SetPercentHeight(UIElement element, Double value)
		{
			element.SetValue(PercentHeightProperty, value);
		}

		public static Double GetPercentHeight(UIElement element)
		{
			return (Double)element.GetValue(PercentHeightProperty);
		}

		#endregion // Attached Properties
		
		protected override Size ArrangeOverride(Size arrangeSize)
		{
			// http://stackoverflow.com/questions/6403091/stackpanel-height-vs-actualheight-vs-extentheight-vs-viewportheight-vs-desiredsi

			double left = 0;
			double top = 0;

			switch (Orientation)
			{
				case System.Windows.Controls.Orientation.Horizontal:

					foreach (UIElement element in InternalChildren)
					{
						var percent = PercentHeightStackPanel.GetPercentHeight(element);

						if (percent <= 0.001)
						{
							if (VisualTreeHelper.GetChildrenCount(element) > 0)
							{
								DependencyObject o = VisualTreeHelper.GetChild(element, 0);
								percent = (double)o.GetValue(PercentHeightProperty);
							}
						}

						if (percent > 100)
						{
							percent = 100;
						}
						else if (percent < 0)
						{
							percent = 0;
						}

						if (percent > 0)
						{
							double height = arrangeSize.Height * (percent / 100.0);
							element.Arrange(new Rect(left, arrangeSize.Height - height, element.DesiredSize.Width, height));
						}
						else
						{
							element.Arrange(new Rect(left, 0, element.DesiredSize.Width, element.DesiredSize.Height));
						}

						left += element.DesiredSize.Width;
					}

					break;

				case System.Windows.Controls.Orientation.Vertical:

					throw new NotImplementedException();
			}

			return arrangeSize;
		}

		protected override Size MeasureOverride(Size constraint)
		{
			/*
			double requestedWidth = 1;
			double requestedHeight = 0;

			var available = new Size(Double.IsNaN(Width) ? constraint.Width : (Width > constraint.Width ? constraint.Width : Width),
				Double.IsNaN(Height) ? constraint.Height : (Height > constraint.Height ? constraint.Height : Height));

			switch (Orientation)
			{
				case System.Windows.Controls.Orientation.Horizontal:

					foreach (UIElement child in InternalChildren)
					{
						child.Measure(available);

						available.Width -= (child.DesiredSize.Width + 1);
						requestedWidth += child.DesiredSize.Width + 1;
					}

					requestedHeight = Double.IsNaN(Height) ? constraint.Height : (Height > constraint.Height ? constraint.Height : Height);

					break;

				case System.Windows.Controls.Orientation.Vertical:

					throw new NotImplementedException();
			}

			// WTF?
			if (double.IsInfinity(requestedWidth))
			{
				requestedWidth = 1;
			}

			// WTF?
			if (double.IsInfinity(requestedHeight))
			{
				requestedHeight = 1000000;
			}

			var parent = VisualTreeHelper.GetParent(this);

			if (parent is UIElement)
			{
				var element = parent as UIElement;
			}

			// GetLayoutClip(
			*/

			if (Orientation == System.Windows.Controls.Orientation.Horizontal)
			{
				return MeasureHorizontal(constraint);
			}

			return MeasureVertical(constraint);
		}

		private Size MeasureHorizontal(Size constraint)
		{
			if (Double.IsNaN(Height) && (Double.IsInfinity(constraint.Height) || Double.IsNaN(constraint.Height)))
			{
				throw new InvalidOperationException("PercentSizeStackPanel should be provided with exact room height on measure step.");
			}

			double desiredHeight = Double.IsNaN(Height) ? constraint.Height : Height;
			double desiredWidth = 0;

			if (!Double.IsNaN(Width) || !Double.IsInfinity(constraint.Width))
			{
				// we have exact width value specified, we should make our children adapt themself for that size.

				desiredWidth = Double.IsNaN(Width) ? constraint.Width : Width;

				double available = desiredWidth;
				foreach (UIElement child in InternalChildren)
				{
					child.Measure(new Size(available, desiredHeight));

					if (available > 0)
					{
						if (child.DesiredSize.Width <= available)
						{
							available -= child.DesiredSize.Width;
						}
						else
						{
							available = 0;
						}
					}
				}
			}
			else
			{
				// we have an infinity width room, lets take part we really needed.

				if (Double.IsInfinity(constraint.Width))
				{
					foreach (UIElement child in InternalChildren)
					{
						child.Measure(new Size(constraint.Width, desiredHeight));
						desiredWidth += child.DesiredSize.Width;
					}
				}
			}

			return new Size(desiredWidth, desiredHeight);
		}

		private Size MeasureVertical(Size constraint)
		{
			throw new NotImplementedException();
		}

		private Size ArrangeHorizontal(Size arrangeSize)
		{
			return new Size();
		}

		private Size ArrangeVertical(Size arrangeSize)
		{
			throw new NotImplementedException();
		}
	}
}
